/* This source file is part of the ATMEL AVR-UC3-SoftwareFramework-1.7.0 Release */

/* This source file is part of the ATMEL AVR32-SoftwareFramework-AT32UC3B-1.4.0 Release */

/*This file is prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
 *
 * \brief Management of the AT25DFX data flash controller through SPI.
 *
 * This file manages the accesses to the AT25DFX data flash components.
 *
 * - Compiler:           IAR EWAVR32 and GNU GCC for AVR32
 * - Supported devices:  All AVR32 devices with an SPI module can be used.
 * - AppNote:
 *
 * \author               Atmel Corporation: http://www.atmel.com \n
 *                       Support and FAQ: http://support.atmel.no/
 *
 ******************************************************************************/

/* Copyright (c) 2009 Atmel Corporation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an Atmel
 * AVR product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
 *
 */

//_____  I N C L U D E S ___________________________________________________


#include "conf_at25dfx.h"
#include "at25dfx.h"

//#if AT25DFX_MEM == ENABLE

#include "compiler.h"
#include "board.h"
#include "gpio.h"
#include "spi.h"
#include "conf_at25dfx.h"
#include "at25dfx.h"
#include "print_funcs.h"
#include "clocks.h"


#if AT25DFX_MEM_CNT > 4
  #error AT25DFX_MEM_CNT must not exceed 4
#endif


//_____ D E F I N I T I O N S ______________________________________________

/*! \name AT25DFX Group A Commands
 */
//! @{
#define AT25DFX_CMD_RD_PAGE              0x0B//kavs0xD2        //!< Main Memory Page Read (Serial/8-bit Mode).

//! @}

/*! \name AT25DFX Group B Commands
 */
//! @{
#define AT25DFX_CMD_PROGRAM				  0x02		 //!< Program byte/page upto 256 bytes only (Serial/8-bit Mode).
#define AT25DFX_CMD_ER_BLOCK_4K           0x20        //!< Block Erase 4K(Serial/8-bit Mode).
#define AT25DFX_CMD_ER_BLOCK_32K          0x52        //!< Block Erase 32 K(Serial/8-bit Mode).
#define AT25DFX_CMD_ER_BLOCK_64K          0xD8        //!< Block Erase 64 K(Serial/8-bit Mode).
#define AT25DFX_CMD_ER_CHIP               0x60  //!< Chip Erase (Serial/8-bit Mode).
#define AT25DFX_CMD_EN_WRITE              0x06  //!< Chip Write Enable (Serial/8-bit Mode).
#define AT25DFX_CMD_DIS_WRITE             0x04  //!< Chip Write Disable (Serial/8-bit Mode).

#define AT25DFX_CMD_PROTECT               0x36
#define AT25DFX_CMD_UNPROTECT             0x39
#define AT25DFX_CMD_RD_SECTOR_PROTECTION  0x3C
//! @}

/*! \name AT25DFX Group C Commands
 */
//! @{
#define AT25DFX_CMDC_RD_STATUS_REG        0x05        //!< Status Register Read (Serial/8-bit Mode).
#define AT25DFX_CMDC_RD_MNFCT_DEV_ID_SM   0x9F        //!< Manufacturer and Device ID Read (Serial Mode).
#define AT25DFX_CMDC_WR_STATUS_REG        0x01
//! @}

/*! \name AT25DFX Group D Commands
 */
//! @{
#define AT25DFX_CMDD_EN_SECTOR_PROT       0x36  //!< Enable Sector Protection (Serial/8-bit Mode).
#define AT25DFX_CMDD_DIS_SECTOR_PROT      0x39  //!< Disable Sector Protection (Serial/8-bit Mode).
#define AT25DFX_CMDD_LKDN_SECTOR          0x33  //!< Sector Lockdown (Serial/8-bit Mode).
#define AT25DFX_CMDD_PR_SECURITY_REG      0x9B  //!< Program Security Register (Serial/8-bit Mode).
#define AT25DFX_CMDD_DEEP_PWR_DN          0xB9        //!< Deep Power-down (Serial/8-bit Mode).
#define AT25DFX_CMDD_RSM_DEEP_PWR_DN      0xAB        //!< Resume from Deep Power-down (Serial/8-bit Mode).
//! @}


/*! \name Bit-Masks and Values for the Manufacture ID and device ID Information
 */
//! @{
#define AT25DFX_MSK_BUSY                  0x01        //!< Busy status bit-mask.
#define AT25DFX_BUSY                      0x01        //!< Busy status value (0x00 when busy, 0x80 when ready).
#define AT25DFX_MSK_DENSITY_FAMILY_CODE   0x44 //kavs      //!< Device density bit-mask.
//! @}

#if AT25DFX_MEM_SIZE == AT25DFX_8MB

/*! \name AT45DB642 Memories
 */
//! @{
#define AT25DFX_DENSITY_FAMILY_CODE       0x44        //!< Device density value.
#define AT25DFX_MANUFACTURER_ID			  0x1F  //!< Manufacturer ID
#define AT25DFX_BYTE_ADDR_BITS            11          //!< Address bits for byte position within buffer.
//! @}

#elif AT25DFX_MEM_SIZE == AT25DFX_05MB

/*! \name AT45DB642 Memories
 */
//! @{
#define AT25DFX_DENSITY_FAMILY_CODE       0x44        //!< Device density value.
#define AT25DFX_MANUFACTURER_ID			  0x1F  //!< Manufacturer ID
#define AT25DFX_BYTE_ADDR_BITS            11          //!< Address bits for byte position within buffer.
//! @}

#else
  #error AT25DFX_MEM_SIZE is not defined to a supported value
#endif

//! Address bits for page selection.
#define AT25DFX_PAGE_ADDR_BITS            (AT25DFX_MEM_SIZE - AT25DFX_PAGE_BITS)

//! Number of bits for addresses within pages.
#define AT25DFX_PAGE_BITS                 (AT25DFX_BYTE_ADDR_BITS - 1)

//! Page size in bytes.
#define AT25DFX_PAGE_SIZE                 (1 << AT25DFX_PAGE_BITS)

//! Bit-mask for byte position within buffer in \ref gl_ptr_mem.
#define AT25DFX_MSK_PTR_BYTE              ((1 << AT25DFX_PAGE_BITS) - 1)

//! Bit-mask for page selection in \ref gl_ptr_mem.
#define AT25DFX_MSK_PTR_PAGE              (((1 << AT25DFX_PAGE_ADDR_BITS) - 1) << AT25DFX_PAGE_BITS)

//! Bit-mask for byte position within sector in \ref gl_ptr_mem.
#define AT25DFX_MSK_PTR_SECTOR            ((1 << AT25DFX_SECTOR_BITS) - 1)


/*! \brief Sends a dummy byte through SPI.
 */



//! Boolean indicating whether memory is in busy state.
static Bool at25dfx_busy;

//! Memory data pointer.
static U32 gl_ptr_mem;

//! Sector buffer.
static U8 sector_buf[AT25DFX_SECTOR_SIZE];





/*! \brief Selects or unselects a DF memory.
 *
 * \param memidx  Memory ID of DF to select or unselect.
 * \param bSelect Boolean indicating whether the DF memory has to be selected.
 */
static void at25dfx_chipselect_df(U8 memidx, Bool bSelect)
{
  if (bSelect)
  {
    // Select SPI chip.
    spi_selectChip(SPI_MODULE, AT25DFX_SPI_NPCS + memidx);
  }
  else
  {
    // Unselect SPI chip.
    spi_unselectChip(SPI_MODULE, AT25DFX_SPI_NPCS + memidx);
  }
}


Bool at25dfx_mem_check(void)
{
  U8 df;
  U16 status,status1,status2;

  // DF memory check.
  for (df = 0; df < AT25DFX_MEM_CNT; df++)
  {
    // Select the DF memory to check.
    at25dfx_chipselect_df(df, TRUE);

    // Send the Manufacturer and Device ID command.
    while(spi_write(SPI_MODULE, AT25DFX_CMDC_RD_MNFCT_DEV_ID_SM)!=SPI_OK);

    // Send a dummy byte to read the status register.
    spi_write_dummy();
    spi_read(SPI_MODULE, &status);
    spi_write_dummy();
    spi_read(SPI_MODULE, &status1);
    spi_write_dummy();
    spi_read(SPI_MODULE, &status2);

    // Unselect the checked DF memory.
    at25dfx_chipselect_df(df, FALSE);

    // Unexpected Manufacturer ID
    if (status  != AT25DFX_MANUFACTURER_ID) return KO;

    // Unexpected device density value & family code
    if ((status1 & AT25DFX_MSK_DENSITY_FAMILY_CODE) < AT25DFX_DENSITY_FAMILY_CODE) return KO;
  }

  return OK;
}


/*! \brief Waits until the DF is ready.
 */
static void at25dfx_wait_ready(void)
{
  U16 status,status1;

  // Select the DF memory gl_ptr_mem points to.
  at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, TRUE);

  // Send the Status Register Read command.
  spi_write(SPI_MODULE, AT25DFX_CMDC_RD_STATUS_REG);

  // Read the status register until the DF is ready.
  do
  {
	  // Send a dummy byte to read the status register.
	  spi_write_dummy();
	  spi_read(SPI_MODULE, &status);
	  spi_write_dummy();
	  spi_read(SPI_MODULE, &status1);
  } while ((status & AT25DFX_MSK_BUSY) == AT25DFX_BUSY);

  // Unselect the DF memory gl_ptr_mem points to.
  at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);
}


Bool at25dfx_read_open(U32 sector)
{


  // Set the global memory pointer to a byte address.
  gl_ptr_mem = sector << AT25DFX_SECTOR_BITS; // gl_ptr_mem = sector * AT25DFX_SECTOR_SIZE.

  // If the DF memory is busy, wait until it's ready.
  at25dfx_wait_ready();
  at25dfx_busy = FALSE;


  // Select the DF memory gl_ptr_mem points to.
  at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, TRUE);

  // Initiate a page read at a given sector.

  // Send the Main Memory Page Read command.
  spi_write(SPI_MODULE, AT25DFX_CMD_RD_PAGE);

  // Send the three address bytes
  spi_write(SPI_MODULE, LSB2W(gl_ptr_mem));
  spi_write(SPI_MODULE, LSB1W(gl_ptr_mem));
  spi_write(SPI_MODULE, LSB0W(gl_ptr_mem));

  spi_write_dummy();

  return OK;
}


void at25dfx_read_close(void)
{
  // Unselect the DF memory gl_ptr_mem points to.
  at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);

  // Memory ready.
  at25dfx_busy = FALSE;
}


Bool at25dfx_write_open(U32 sector)
{
  // Set the global memory pointer to a byte address.
  gl_ptr_mem = sector << AT25DFX_SECTOR_BITS; // gl_ptr_mem = sector * AT25DFX_SECTOR_SIZE.

  // If the DF memory is busy, wait until it's ready.
  at25dfx_wait_ready();
  at25dfx_busy = FALSE;


  at25dfx_write_enable();

  at25dfx_wait_ready();

  // Select the DF memory gl_ptr_mem points to.
    at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, TRUE);

    // Send the Main Memory Page to Buffer 1 Transfer command.
    spi_write(SPI_MODULE, AT25DFX_CMD_PROGRAM);


	spi_write(SPI_MODULE, LSB2W(gl_ptr_mem));
	spi_write(SPI_MODULE, LSB1W(gl_ptr_mem));
	spi_write(SPI_MODULE, LSB0W(gl_ptr_mem));

  return OK;
}


void at25dfx_write_close(void)
{
  // While end of logical sector not reached, zero-fill remaining memory bytes.
  while (Rd_bitfield(gl_ptr_mem, AT25DFX_MSK_PTR_SECTOR))
  {
    spi_write(SPI_MODULE, 0x00);
    gl_ptr_mem++;
  }

  // Unselect the DF memory gl_ptr_mem points to.
  at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);

  at25dfx_wait_ready();

  // Stop further writes to memory.
  at25dfx_write_disable();


  // Memory busy.
  at25dfx_busy = FALSE; //xxxTRUE;// xxx
}


//! @}


/*! \name Single-Byte Access Functions
 */
//! @{


U8 at25dfx_read_byte(void)
{
  U16 data;

  // Memory busy.
  if (at25dfx_busy)
  {
    // Being here, we know that we previously finished a page read.
    // => We have to access the next page.

    // Memory ready.
    at25dfx_busy = FALSE;

    // Eventually select the next DF and open the next page.
    // NOTE: at25dfx_read_open input parameter is a sector.
    at25dfx_read_open(gl_ptr_mem >> AT25DFX_SECTOR_BITS); // gl_ptr_mem / AT25DFX_SECTOR_SIZE.
  }

  // Send a dummy byte to read the next data byte.
  spi_write_dummy();
  spi_read(SPI_MODULE, &data);
  gl_ptr_mem++;

  // If end of page reached,
  if (!Rd_bitfield(gl_ptr_mem, AT25DFX_MSK_PTR_BYTE))
  {
    // unselect the DF memory gl_ptr_mem points to.
    at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);

    // Memory busy.
    at25dfx_busy = TRUE;
  }

  return data;
}


Bool at25dfx_write_byte(U8 b)
{
  // Memory busy.
  if (at25dfx_busy)
  {
    // Being here, we know that we previously launched a page programming.
    // => We have to access the next page.

    // Eventually select the next DF and open the next page.
    // NOTE: at25dfx_write_open input parameter is a sector.
    at25dfx_write_open(gl_ptr_mem >> AT25DFX_SECTOR_BITS); // gl_ptr_mem / AT25DFX_SECTOR_SIZE.
  }


  // Write the next data byte.
  spi_write(SPI_MODULE, b);

  gl_ptr_mem++;

  // If end of page reached,
  if (!Rd_bitfield(gl_ptr_mem, AT25DFX_MSK_PTR_BYTE))
  {
    // unselect the DF memory gl_ptr_mem points to in order to program the page.
    at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);

    // Memory busy.
    at25dfx_busy = TRUE;
  }

  return OK;
}


//! @}


/*! \name Multiple-Sector Access Functions
 */
//! @{


Bool at25dfx_read_multiple_sector(U16 nb_sector)
{
  while (nb_sector--)
  {
    // Read the next sector.
    at25dfx_read_sector_2_ram(sector_buf);
    at25dfx_read_multiple_sector_callback(sector_buf);
  }

  return OK;
}


Bool at25dfx_write_multiple_sector(U16 nb_sector)
{
  while (nb_sector--)
  {
    // Write the next sector.
    at25dfx_write_multiple_sector_callback(sector_buf);
    at25dfx_write_sector_from_ram(sector_buf);
  }

  return OK;
}


//! @}


/*! \name Single-Sector Access Functions
 */
//! @{


Bool at25dfx_read_sector_2_ram(void *ram)
{
  U8 *_ram = ram;
  U16 i;
  U16 data;

  // Read the next sector.
  for (i = AT25DFX_SECTOR_SIZE; i; i--)
  {
    // Send a dummy byte to read the next data byte.
    spi_write_dummy();
    spi_read(SPI_MODULE, &data);
    *_ram++ = data;
  }

  // Update the memory pointer.
  gl_ptr_mem += AT25DFX_SECTOR_SIZE;

  return OK;
}


Bool at25dfx_write_sector_from_ram(const void *ram)
{
  const U8 *_ram = ram;
  U16 i;

  // Memory busy.
  if (at25dfx_busy)
  {
    // Being here, we know that we previously launched a page programming.
    // => We have to access the next page.

    // Eventually select the next DF and open the next page.
    // NOTE: at25dfx_write_open input parameter is a sector.
    at25dfx_write_open(gl_ptr_mem >> AT25DFX_SECTOR_BITS); // gl_ptr_mem / AT25DFX_SECTOR_SIZE.
  }

  // Write the next sector.
  for (i = AT25DFX_SECTOR_SIZE; i; i--)
  {
    // Write the next data byte.
    spi_write(SPI_MODULE, *_ram++);
  }

  // Update the memory pointer.
  gl_ptr_mem += AT25DFX_SECTOR_SIZE;

#if AT25DFX_PAGE_SIZE > AT25DFX_SECTOR_SIZE
  // If end of page reached,
  //if (!Rd_bitfield(gl_ptr_mem, AT25DFX_MSK_PTR_BYTE))
#endif
  {
    // unselect the DF memory gl_ptr_mem points to in order to program the page.
    at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);

    // Memory busy.
    at25dfx_busy = TRUE;
  }

  return OK;
}

void at25dfx_write_enable(void)
{
	at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, TRUE);
	while(spi_write(SPI_MODULE, AT25DFX_CMD_EN_WRITE)!=SPI_OK);//write enable;
	at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);
}
void at25dfx_write_disable(void)
{
	at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, TRUE);
	while(spi_write(SPI_MODULE, AT25DFX_CMD_DIS_WRITE)!=SPI_OK);//write enable;
	at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);
}

void at25dfx_4k_block_erase(U32 block)
{
	U32 addr;
	at25dfx_write_enable();
	// Set the global memory pointer to a byte address.
	//gl_ptr_mem = sector << AT25DFX_SECTOR_BITS; // gl_ptr_mem = sector * AT25DFX_SECTOR_SIZE.
	gl_ptr_mem = block << 12; // gl_ptr_mem = sector * AT25DFX_SECTOR_SIZE.

	at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, TRUE);
	addr = gl_ptr_mem;
	while(spi_write(SPI_MODULE, AT25DFX_CMD_ER_BLOCK_4K)!=SPI_OK);//write enable;
	spi_write(SPI_MODULE, LSB2W(addr));
	spi_write(SPI_MODULE, LSB1W(addr));
	spi_write(SPI_MODULE, LSB0W(addr));
	at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);
	at25dfx_wait_ready();
	at25dfx_write_disable();

}

void at25dfx_chip_erase(void)
{
	at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, TRUE);
	while(spi_write(SPI_MODULE, AT25DFX_CMD_ER_CHIP)!=SPI_OK);//write enable;
	at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);
	at25dfx_wait_ready();

}

U16 at25dfx_status(void)
{
  U16 status;

  // Select the DF memory gl_ptr_mem points to.
  at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, TRUE);

  // Send the Status Register Read command.
  spi_write(SPI_MODULE, AT25DFX_CMDC_RD_STATUS_REG);

  // Read the status register .
  // Send a dummy byte to read the status register.
  spi_write_dummy();
  spi_read(SPI_MODULE, &status);

  // Unselect the DF memory gl_ptr_mem points to.
  at25dfx_chipselect_df(gl_ptr_mem >> AT25DFX_MEM_SIZE, FALSE);

  return status;

}

Bool at25dfx_unprotect(U32 sector)
{
  // Set the global memory pointer to a byte address.
  U32 address = sector << AT25DFX_SECTOR_BITS; // gl_ptr_mem = sector * AT25DFX_SECTOR_SIZE.

  // If the DF memory is busy, wait until it's ready.
  at25dfx_wait_ready();



  // Select the DF memory gl_ptr_mem points to.
    at25dfx_chipselect_df(address >> AT25DFX_MEM_SIZE, TRUE);

    // Send the Main Memory Page to Buffer 1 Transfer command.
    spi_write(SPI_MODULE, AT25DFX_CMD_UNPROTECT);


	spi_write(SPI_MODULE, LSB2W(address));
	spi_write(SPI_MODULE, LSB1W(address));
	spi_write(SPI_MODULE, LSB0W(address));

	at25dfx_chipselect_df(address >> AT25DFX_MEM_SIZE, FALSE);

	at25dfx_status();


  return OK;
}

U16 at25dfx_Read_Sector_Protection_Register(U32 sector)
{
  // Set the global memory pointer to a byte address.
  U32 address = sector << AT25DFX_SECTOR_BITS; // gl_ptr_mem = sector * AT25DFX_SECTOR_SIZE.
  U16 result;
  // If the DF memory is busy, wait until it's ready.
  at25dfx_wait_ready();


  // Select the DF memory gl_ptr_mem points to.
    at25dfx_chipselect_df(address >> AT25DFX_MEM_SIZE, TRUE);

    // Send the Main Memory Page to Buffer 1 Transfer command.
    spi_write(SPI_MODULE, AT25DFX_CMD_RD_SECTOR_PROTECTION);


	spi_write(SPI_MODULE, LSB2W(gl_ptr_mem));
	spi_write(SPI_MODULE, LSB1W(gl_ptr_mem));
	spi_write(SPI_MODULE, LSB0W(gl_ptr_mem));

	spi_write_dummy();
	spi_read(SPI_MODULE, &result);

	at25dfx_chipselect_df(address >> AT25DFX_MEM_SIZE, FALSE);


  return result;
}

Bool at25dfx_global_unprotect(void)
{
  // If the DF memory is busy, wait until it's ready.
  at25dfx_wait_ready();
  at25dfx_write_enable();


    at25dfx_chipselect_df(0, TRUE);

    spi_write(SPI_MODULE, AT25DFX_CMDC_WR_STATUS_REG);


	spi_write(SPI_MODULE, 0x00);

	at25dfx_chipselect_df(0, FALSE);
	at25dfx_write_disable();

	at25dfx_status();

  return OK;
}

Bool at25dfx_read_sector(int start_sector,int sector_count,unsigned char * buffer)
{
    U32 i,j;
/*    if(start_sector >= 2047)
    	start_sector = 10;*/
    for(i = 0 ; i < sector_count ; i++)
    {
    	at25dfx_read_open(start_sector + i);
    	for (j = 0; j < AT25DFX_SECTOR_SIZE ; j++)
    	{
    		*buffer = at25dfx_read_byte();
    		buffer++;
    	}
    	at25dfx_read_close();
    }
    return OK;
}

Bool at25dfx_read_bytes(int byte_address,int byte_count,unsigned char * buffer)
{
	U32 sector = byte_address / AT25DFX_SECTOR_SIZE;
	U32 magnitude = byte_address % AT25DFX_SECTOR_SIZE;
    U32 i;
    at25dfx_read_open(sector);
    for(i = 0 ; i < magnitude ; i++)
    	at25dfx_read_byte();
    for(i = 0 ; i < byte_count ; i++)
    {
    	*buffer = at25dfx_read_byte();
    	buffer++;
    }
    at25dfx_read_close();
    return OK;
}
Bool at25dfx_write_sector(int start_sector,int sector_count,unsigned char * buffer)
{
    U32 i,j;
    for(i = 0 ; i < sector_count ; i++)
    {
    	at25dfx_write_open(start_sector + i);
    	for (j = 0; j < AT25DFX_SECTOR_SIZE ; j++)
    	{
    		at25dfx_write_byte(*buffer);
    		buffer++;
    	}
    	at25dfx_write_close();
    }
    return OK;
}

Bool at25dfx_erase_all(void)
{
	at25dfx_wait_ready();
	at25dfx_write_enable();
	at25dfx_chip_erase();
	at25dfx_write_disable();
    return OK;
}

Bool at25dfx_erase(int sector_address, int sector_count)
{
	int block_address = (sector_address << AT25DFX_SECTOR_BITS) >> 12;
	int block_count = (sector_count << AT25DFX_SECTOR_BITS) >> 12;
	int i;
	for(i = 0 ; i < block_count ; i++)
	{
		at25dfx_4k_block_erase(block_address + i);
	}
    return OK;
}

/*! \brief Initializes AT25DFX resources: GPIO, SPI and AT25DFX.
 */
void at25dfx_resources_init(void)
{
  at25dfx_busy = FALSE;
  if(at25dfx_mem_check())
	  at25dfx_global_unprotect();
  //at25dfx_init(spiOptions, FPBA_HZ);
}


//! @}


//#endif  // AT25DFX_MEM == ENABLE
